#set( $symbol_pound = '#' )
#set( $symbol_dollar = '$' )
#set( $symbol_escape = '\' )
/*
 * Copyright © 2014, Finium Sdn Bhd, All Rights Reserved
 * 
 * SchedulerJobUtil.java
 * Modification History
 * *************************************************************
 * Date				Author						Comment
 * Oct 11, 2012		Venkaiah Chowdary Koneru	Created
 * *************************************************************
 */
package ${package}.support.scheduling;

import java.text.ParseException;
import java.util.Date;
import java.util.Map;

import ${package}.support.CommonsUtil;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.quartz.CronTrigger;
import org.quartz.JobDataMap;
import org.quartz.JobDetail;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.quartz.SimpleTrigger;
import org.quartz.Trigger;
import org.springframework.util.StringUtils;

/**
 * Utility class which contains the methods related to Scheduling jobs.
 * 
 * @author Venkaiah Chowdary Koneru
 */
public final class SchedulerJobUtil
{
    /**
     * Scheduler Job Groups prefix
     */
    static final String JOB_GROUP_PREFIX = "Group_";

    /**
     * Scheduler Jobs Trigger prefix
     */
    static final String JOB_TRIGGER_PREFIX = "Trigger_";

    private static final Log LOG = LogFactory.getLog(SchedulerJobUtil.class);

    /**
     * Register a job with the given name. It will unregister if any existing
     * jobs with the same name.
     * 
     * @param scheduler
     * @param jobName
     * @param dataMap
     * @param cronExpression
     * @param clazz
     *            subclass of AbstractJob
     * @throws SchedulerException
     *             in case if error in schedule job
     * @throws ParseException
     *             in case if cron expression parse error
     * @throws Exception
     */
    public static void registerJob(final Scheduler scheduler,
            final String jobName, final String cronExpression,
            final Long startTimeInMillis, Class<? extends AbstractJob> clazz,
            Map<String, ?> dataMap) throws SchedulerException, ParseException
    {
        // unregister job
        unregisterJob(scheduler, jobName, getJobGroupName(jobName));

        // JobDetail
        JobDetail jobDetail = constructJobdetail(jobName, clazz, dataMap);

        Trigger trigger = null;
        // Trigger
        if (!StringUtils.hasText(cronExpression))
        {
            trigger = constructSimpleTrigger(jobName,
                    startTimeInMillis.longValue());

            scheduler.scheduleJob(jobDetail, trigger);
        }
        else
        {
            trigger = constructCronTrigger(jobName, cronExpression);

            scheduler.scheduleJob(jobDetail, trigger);
        }

        if (LOG.isDebugEnabled())
        {
            LOG.debug("Scheduled a Job with job name as " + jobDetail.getName()
                    + " and group name as " + jobDetail.getGroup());

            if (trigger instanceof SimpleTrigger)
            {
                LOG.debug("Scheduled to run at " + trigger.getNextFireTime());
            }
            else if (trigger instanceof CronTrigger)
            {
                LOG.debug("Scheduled to fire next at "
                        + trigger.getNextFireTime());
            }
        }
    }

    /**
     * Unregister the jobs from scheduler.
     * 
     * @param scheduler
     * @param jobName
     * @param jobGroupName
     *            exact group name
     */
    public static void unregisterJob(final Scheduler scheduler,
            final String jobName, final String jobGroupName)
    {
        if (LOG.isDebugEnabled())
        {
            LOG.debug("Requested for a job[" + jobName + "] unschedule.");
        }

        try
        {
            if (LOG.isTraceEnabled())
            {
                LOG.trace("process unschedule job[" + jobName + "].");
            }

            scheduler.unscheduleJob(jobName, jobGroupName);

            if (LOG.isTraceEnabled())
            {
                LOG.trace("Delete job[" + jobName + "] from scheduler.");
            }

            scheduler.deleteJob(jobName, jobGroupName);
        }
        catch (SchedulerException e)
        {
            if (LOG.isErrorEnabled())
            {
                LOG.error("Could not remove job " + jobName, e);
            }
        }
    }

    /**
     * returns job trigger name for the given job name
     * 
     * @param jobName
     * @return trigger name for the given job name
     */
    public static String getTriggerName(final String jobName)
    {
        return JOB_TRIGGER_PREFIX + jobName;
    }

    /**
     * returns job group name for the given job name.
     * 
     * @param jobName
     * @return group name for the given job name
     */
    public static String getJobGroupName(final String jobName)
    {
        return JOB_GROUP_PREFIX + jobName;
    }

    /**
     * 
     * @param jobName
     * @param clazz
     * @return job detail instance
     */
    private static JobDetail constructJobdetail(final String jobName,
            Class<? extends AbstractJob> clazz, final Map<String, ?> dataMap)
    {
        JobDetail jobDetail = new JobDetail();
        jobDetail.setName(jobName);
        jobDetail.setGroup(getJobGroupName(jobName));
        jobDetail.setJobClass(clazz);

        if (!CommonsUtil.isEmpty(dataMap))
        {
            jobDetail.setJobDataMap(new JobDataMap(dataMap));
        }

        return jobDetail;
    }

    /**
     * 
     * @param jobName
     * @param startTimeInMillis
     * @return simple trigger instance
     */
    private static SimpleTrigger constructSimpleTrigger(final String jobName,
            long startTimeInMillis)
    {
        SimpleTrigger simpleTrigger = new SimpleTrigger();
        simpleTrigger.setName(getTriggerName(jobName));
        simpleTrigger.setStartTime(new Date(startTimeInMillis));

        return simpleTrigger;
    }

    /**
     * 
     * @param jobName
     * @param cronExpression
     * @return cron trigger instance
     * @throws ParseException
     */
    private static CronTrigger constructCronTrigger(final String jobName,
            final String cronExpression) throws ParseException
    {
        CronTrigger cronTrigger = new CronTrigger();
        cronTrigger.setName(getTriggerName(jobName));
        cronTrigger.setCronExpression(cronExpression);

        return cronTrigger;
    }

    /**
     * Private default Constructor.
     */
    private SchedulerJobUtil()
    {

    }
}
